package cn.brilliantfuture.commentry.lockers.impl;

import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;
import javax.ejb.EJB;
import javax.ejb.SessionContext;
import javax.ejb.Stateless;
import javax.ejb.TransactionManagement;
import javax.ejb.TransactionManagementType;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.transaction.UserTransaction;

import net.sf.json.JSONArray;
import net.sf.json.JSONObject;

import org.apache.log4j.Logger;

import cn.brilliantfuture.commentry.constants.OrderConstant;
import cn.brilliantfuture.commentry.entity.DataModels;
import cn.brilliantfuture.commentry.entity.DeliveryPlan;
import cn.brilliantfuture.commentry.entity.Lockers;
import cn.brilliantfuture.commentry.entity.OrderInformation;
import cn.brilliantfuture.commentry.entity.ProductBatch;
import cn.brilliantfuture.commentry.entity.Purchaser;
import cn.brilliantfuture.commentry.entity.StorageGrid;
import cn.brilliantfuture.commentry.entity.StorageGridPurchaserNews;
import cn.brilliantfuture.commentry.entity.UserGroup;
import cn.brilliantfuture.commentry.inform.InformMessageLocal;
import cn.brilliantfuture.commentry.lockers.DeliverStoreMessageLocal;
import cn.brilliantfuture.commentry.order.WorkflowMessageLocal;
import cn.brilliantfuture.commentry.util.BaseMessageImpl;
import cn.brilliantfuture.commentry.util.CRC8;
import cn.brilliantfuture.commentry.util.CommEntryUtil;
import cn.brilliantfuture.commentry.util.DateTimeHelper;
import cn.brilliantfuture.commentry.util.HttpUtil;

/**
 * 
 * Title: Communication Entry
 * 
 * Author:  LiTian  
 *
 * Date: 2013-6-13
 * 
 * Description:
 * 
 */
@Stateless
@TransactionManagement(TransactionManagementType.BEAN)
public class DeliverStoreMessageImpl extends BaseMessageImpl implements DeliverStoreMessageLocal {
	
	protected static final Logger logger = Logger.getLogger(DeliverStoreMessageImpl.class);
	
	@PersistenceContext(unitName = "commentry-jpa")
	private EntityManager entityManager;
	
	@Resource
	SessionContext sessionContext;
	
	@EJB InformMessageLocal informMessage;
	
	@EJB WorkflowMessageLocal workflowMessageLocal;

	@SuppressWarnings("unchecked")
	public JSONObject createStoreReserve(int userId, int groupId, int lockersId, int serviceType, int storeType, int gridType, long beginTime, long endTime) {
		
		logger.info("userId -> " + userId + " groupId -> " + groupId + " lockersId -> " + lockersId + " serviceType -> " + serviceType + " storeType -> " + storeType + " gridType -> " + gridType + " beginTime -> " + beginTime + " endTime -> " + endTime);
		
		List<Lockers> lockersList = entityManager.createQuery("select l from Lockers l where l.storageBusiness = true and l.lockersId = " + lockersId).getResultList();
		
		if (null == lockersList || lockersList.size() == 0){
			return null;
		}
		
		Lockers lockers = lockersList.get(0);
		
		String area = lockers.getLocation().getVilliage().getArea().getArea().getArea().getName() + lockers.getLocation().getVilliage().getArea().getArea().getName() + lockers.getLocation().getVilliage().getArea().getName();
		String address = lockers.getLocation().getVilliage().getName() + lockers.getLocation().getName() + lockers.getLockersName();
		String deviceSn = lockers.getDevice().getDeviceSn();
		DeliveryPlan deliveryPlan = deliverPlanFilter(lockersId, storeType, gridType, beginTime, endTime);
		
		if (null == deliveryPlan){
			logger.info("Delivery plan reserve fail!");
			return null;
		}

		UserGroup group = new UserGroup();
		group.setGroupId(groupId);
		Purchaser purchaser = entityManager.find(Purchaser.class, userId);
		
		OrderInformation orderInformation = new OrderInformation();
		orderInformation.setNumber(group.getGroupId() + String.valueOf(System.currentTimeMillis()));
		orderInformation.setPurchaser(purchaser);
		orderInformation.setReceiveName(purchaser.getRealname());
		orderInformation.setReceivePhone(purchaser.getPhone());
		orderInformation.setRecevieEmail(purchaser.getEmail());
		orderInformation.setLockers(lockers);
		orderInformation.setGroup(group);
		orderInformation.setStoreMode(OrderConstant.GENERAL_STORE_TYPE);
		orderInformation.setPaymentMode(OrderConstant.VIGGIEHOME_PAYMENT_MODE);
		orderInformation.setTotalAmount(0.0D);
		orderInformation.setOrderSource(OrderConstant.ORDER_SOURCE_VIGGIEHOME);
		orderInformation.setOrderType(OrderConstant.STORAGE_ORDER_TYPE);
		orderInformation.setTransactions(OrderConstant.DONE_SORT);
		orderInformation.setDataModels(null);
		orderInformation.setEffective(true);
		orderInformation.setManual(false);
		orderInformation.setDeleted(false);
		orderInformation.setInsertTime(new Date());
		
		ProductBatch productBatch = new ProductBatch();
		productBatch.setOrderInformation(orderInformation);
		productBatch.setInsertTime(new Date());
		
		if (storeType == 1) {
			productBatch.setStoreMode(1);
		} else if (storeType == 2) {
			productBatch.setStoreMode(4);
			DataModels dataModels = entityManager.find(DataModels.class, 4);
			productBatch.setDataModelValue(dataModels.getLowerLimit() + "," + dataModels.getUpperLimit());
		} else if (storeType == 3) {
			productBatch.setStoreMode(3);
			DataModels dataModels = entityManager.find(DataModels.class, 3);
			productBatch.setDataModelValue(dataModels.getLowerLimit() + "," + dataModels.getUpperLimit());
		}

		productBatch.setDeleted(false);
		
		autoCreateRfid(productBatch, lockers.getLockersSn());
		
		deliveryPlan.setOrderInformation(orderInformation);
		deliveryPlan.setProductBatch(productBatch);

		StringBuffer sb = new StringBuffer();
		sb.append(getRemoteUrl()).append("/deliveryplan/?").append("deviceSn=");
		sb.append(deviceSn).append("&gridNum=").append(deliveryPlan.getStorageGrid().getGridNum());
		sb.append("&businessType=").append(2);
		sb.append("&storeMode=").append(productBatch.getStoreMode());
		sb.append("&rfidSn=").append(productBatch.getRfidSn());
		sb.append("&beginTime=").append(DateTimeHelper.dateTimeToStr(deliveryPlan.getBeginTime(), "yyyyMMddHHmm")).append("00&endTime=").append(DateTimeHelper.dateTimeToStr(deliveryPlan.getEndTime(), "yyyyMMddHHmm")).append("59");
		sb.append("&planType=").append(1);
		
		String invoke = HttpUtil.getInvoke(sb.toString());
		if (!"1".equals(invoke)) {
			logger.info("ADCP delivery plan reserve fail!");
			return null;
		}
		
		UserTransaction ut = sessionContext.getUserTransaction();
		
		try {
			ut.begin();
			
			entityManager.persist(orderInformation);
			entityManager.persist(productBatch);
			entityManager.persist(deliveryPlan);
			
			workflowMessageLocal.createWorkflowInfo(orderInformation, 1, "生成配送单...", new Date(), "系统", 4);
			
			workflowMessageLocal.createWorkflowInfo(orderInformation, 2, "生成收储编号" + productBatch.getRfidSn(), new Date(), "系统", 4);
			
			ut.commit();
			
			JSONObject result = new JSONObject();
			result.accumulate("store_code", productBatch.getRfidSn());
			result.accumulate("store_passwd", productBatch.getPasswd());
			result.accumulate("area", area);
			result.accumulate("address", address);
			
			return result;
			
		} catch (Exception e) {
			try {
				ut.rollback();
			} catch (Exception e1) {
				logger.error("Rollback fail\n" + e1.getMessage());
			}
			logger.error("Create store reserve info fail!\n" + e.getMessage());
		}
		
		logger.info("Delivery plan reserve null!");
		
		return null;
	}

	@SuppressWarnings("unchecked")
	private void autoCreateRfid(ProductBatch productBatch, String lockersSn){
		
		String rfid = randomRfid();
		
		rfid += CommEntryUtil.transferCheckBit(CommEntryUtil.getFormatStr(CRC8.getCRC(rfid, Integer.parseInt(lockersSn)), 2));
		
		String passwd = CommEntryUtil.confuse(calculatePasswd(CommEntryUtil.bernstein(rfid)));
		
		List<Object> rfidList = entityManager.createQuery("select pb.rfidSn from ProductBatch pb where pb.rfidSn = '" + rfid + "'").getResultList();
		
		if (null != rfidList && rfidList.size() > 0)
			autoCreateRfid(productBatch, lockersSn);
		
		List<Object> passwdList = entityManager.createQuery("select pb.rfidSn from ProductBatch pb inner join pb.orderInformation oi where oi.transactions != 7 and pb.passwd = '" + passwd + "'").getResultList();
		
		if (null != passwdList && passwdList.size() > 0)
			autoCreateRfid(productBatch, lockersSn);
		
		productBatch.setRfidSn(rfid);
		productBatch.setPasswd(passwd);
	}

	private String randomRfid() {
		String rfid = String.valueOf((long) (Math.random() * 1000000));

		while (rfid.length() < 6) {
			rfid += String.valueOf((long) (Math.random() * 10));
		}

		return rfid;
	}

	private static String calculatePasswd(String rfid_sn) {
		StringBuffer sb = new StringBuffer();
		String done = rfid_sn.substring(7, 19);
		sb.append(done.charAt(3));
		sb.append(done.charAt(7));
		sb.append(done.charAt(4));
		sb.append(done.charAt(10));
		sb.append(done.charAt(2));
		sb.append(done.charAt(5));
		return sb.toString();
	}

	@SuppressWarnings("unchecked")
	public JSONArray getStorePointList() {
		JSONArray result = new JSONArray();
		
		List<Object[]> villageList = entityManager.createNativeQuery("select * from (select vl.villiage_id, vl.province_name, vl.city_name, vl.county_name, vl.villiage_name, vl.longitude, vl.latitude from view_lockers vl where vl.lockers_used = 1 and vl.storage_business = true group by vl.villiage_id) as test").getResultList();
		
		Map<Integer, JSONObject> map = new HashMap<Integer, JSONObject>();
		
		for (Object[] objs : villageList) {
			JSONObject village = new JSONObject();
			village.accumulate("area", objs[1].toString() + objs[2].toString() + objs[3].toString());
			village.accumulate("village", objs[4].toString());
			village.accumulate("longitude", objs[5]);
			village.accumulate("latitude", objs[6]);
			
			village.accumulate("lockers_infos", new JSONArray());
			
			map.put((Integer)objs[0], village);
		}
		
		List<Object[]> lockersList = entityManager.createNativeQuery("select * from (select vl.villiage_id, vl.lockers_id, vl.location_name, vl.lockers_name from view_lockers vl where vl.lockers_used = 1 and vl.storage_business = true group by vl.lockers_id) as test").getResultList(); 
		
		for (Object[] objs : lockersList) {
			JSONObject lockers = new JSONObject();
			lockers.accumulate("lockers_id", objs[1]);
			lockers.accumulate("location", objs[2]);
			lockers.accumulate("lockers_name", objs[3]);
			
			JSONObject village = map.get((Integer)objs[0]);
			
			JSONArray lcokersInfos = village.getJSONArray("lockers_infos");
			
			lcokersInfos.add(lockers);
		}

		for (JSONObject village : map.values()) {
			result.add(village);
		}

		return result;
	}

	@SuppressWarnings("unchecked")
	public boolean createStoreUnreserve(String storeCode) {
		
		logger.info("storeCode -> " + storeCode);
		
		List<DeliveryPlan> deliveryPlans = entityManager.createQuery("select dp from DeliveryPlan dp where dp.planType = 1 and dp.productBatch.rfidSn = '" + storeCode + "'").getResultList();

		if (deliveryPlans.size() == 0){
			return false;
		}
		
		DeliveryPlan deliveryPlan = deliveryPlans.get(0);
		
		StringBuffer sb = new StringBuffer();
		sb.append(getRemoteUrl()).append("/deliveryplan/?").append("deviceSn=");
		sb.append(deliveryPlan.getLockers().getDevice().getDeviceSn()).append("&gridNum=").append(deliveryPlan.getStorageGrid().getGridNum());
		sb.append("&storeMode=").append(deliveryPlan.getProductBatch().getStoreMode());
		sb.append("&rfidSn=").append(deliveryPlan.getProductBatch().getRfidSn());
		sb.append("&businessType=").append(2);
		sb.append("&beginTime=").append(DateTimeHelper.dateTimeToStr(deliveryPlan.getBeginTime(), "yyyyMMddHHmm")).append("00&endTime=").append(DateTimeHelper.dateTimeToStr(deliveryPlan.getEndTime(), "yyyyMMddHHmm")).append("00");
		sb.append("&planType=").append(2);
		String result = HttpUtil.getInvoke(sb.toString());
		
		if (!"1".equals(result)){
			return false;
		}
		
		UserTransaction ut = sessionContext.getUserTransaction();
		
		try {
			ut.begin();
			
			deliveryPlan.setPlanType(2);
			deliveryPlan.setPublish(false);
			
			entityManager.merge(deliveryPlan);
			entityManager.flush();
			
			ut.commit();
			return true;
		} catch (Exception e) {
			try {
				ut.rollback();
			} catch (Exception e1) {
				logger.error("Rollback fail\n" + e1.getMessage());
			}
			logger.error("Save unreserve plan fail!\n" + e.getMessage());
			return false;
		}
		
	}
	
	@SuppressWarnings("unchecked")
	private DeliveryPlan deliverPlanFilter(Integer lockersId, int storeType, int gridType, long beginTime, long endTime){
		logger.info("Delivery plan filter ...");
		
		//拼接语句查询是否已有配送计划
		StringBuffer existPlanSql = new StringBuffer();
		
		existPlanSql.append("select sg.storage_grid_id from delivery_plan dp inner join storage_grid sg on dp.storage_grid_id =  sg.storage_grid_id inner join order_information oi on dp.order_information_id = oi.order_information_id left  join storage_grid_purchaser_news sgpn on sgpn.delivery_plan_id = dp.delivery_plan_id where oi.transactions <=6 and (sgpn.storage_grid_purchaser_news_id is null or (sgpn.closing = 0 and sgpn.pick = 0)) and (dp.plan_type = 1 or (dp.plan_type = 2 and dp.publish = 0))");

		if (lockersId != null && beginTime != 0 && endTime != 0) {
			existPlanSql.append(" and sg.lockers_id = ").append(lockersId);
			existPlanSql.append(" and sg.business_type = 2");
			
			if (storeType == 1) {
				existPlanSql.append(" and sg.grid_type = 1");
			} else if (storeType == 2 || storeType == 3){
				existPlanSql.append(" and sg.grid_type = 3");
			}
			existPlanSql.append(" and sg.grid_size = ").append(gridType);
			//existPlanSql.append(" and dp.endTime < '").append(DateTimeHelper.dateTimeToStr(new Date(beginTime), DateTimeHelper.DEFAULT_DATE_TIME_FORMAT)).append("'");
			//existPlanSql.append(" and dp.endTime <= '").append(DateTimeHelper.dateTimeToStr(new Date(endTime), DateTimeHelper.DEFAULT_DATE_TIME_FORMAT)).append("'");
		} else {
			return null;
		}
		
		List<Integer> existPlanList = entityManager.createNativeQuery(existPlanSql.toString()).getResultList();

		
		/*List<DeliveryPlan> existPlanList = entityManager.createQuery(existPlanSql.toString()).getResultList();

		if (existPlanList.size() > 0){
			for (Iterator<DeliveryPlan> it = existPlanList.iterator(); it.hasNext();) {
				DeliveryPlan deliveryPlan = it.next();
				if (null != deliveryPlan.getStorageGridPurchaserNews()){
					if (deliveryPlan.getStorageGridPurchaserNews().getClosing().intValue() == 1 && deliveryPlan.getStorageGridPurchaserNews().getPick().intValue() == 1){
						it.remove();
					}
				}
			}
		}
		
		for (Iterator<DeliveryPlan> it = existPlanList.iterator(); it.hasNext();) {
			DeliveryPlan deliveryPlan = it.next();
			if (deliveryPlan.getOrderInformation().getTransactions().intValue() > 6) {
				it.remove();
			}
		}*/
		
		/*if (existPlanList.size() > 0){
			//过滤计划时间
			for (Iterator it = existPlanList.iterator(); it.hasNext();) {
				DeliveryPlan deliveryPlan = (DeliveryPlan) it.next();
				if (beginTime < deliveryPlan.getBeginTime().getTime() && endTime <= deliveryPlan.getBeginTime().getTime()){
					it.remove();
				}else if (beginTime >= deliveryPlan.getEndTime().getTime() && endTime > deliveryPlan.getEndTime().getTime()){
					it.remove();
				}
			}
		}*/
			
		StringBuffer storageGridSql = new StringBuffer();
		storageGridSql.append("select sg from StorageGrid sg where sg.deleted = 0");
		
		if (storeType == 1) {
			storageGridSql.append(" and sg.gridType = 1");
		} else if (storeType == 2 || storeType == 3){
			storageGridSql.append(" and sg.gridType = 3");
		}
		storageGridSql.append(" and sg.gridSize = ").append(gridType);
		storageGridSql.append(" and sg.lockers.lockersId = ").append(lockersId);
		storageGridSql.append(" and sg.businessType = 2");
		
		if (existPlanList.size() > 0){
			storageGridSql.append(" and sg.storageGridId not in (");
			
			for (int i = 0; i < existPlanList.size(); i++){
				storageGridSql.append(existPlanList.get(i));
				if (i < existPlanList.size() - 1)
					storageGridSql.append(",");
			}
			
			storageGridSql.append(")");
		}

		//获取可用仓门数据
		List<StorageGrid> storageGridList = entityManager.createQuery(storageGridSql.toString()).getResultList();
		
		if (storageGridList.size() > 0){
			DeliveryPlan deliveryPlan = new DeliveryPlan();
			deliveryPlan.setBeginTime(new Date(beginTime));
			deliveryPlan.setEndTime(new Date(endTime));
			deliveryPlan.setPlanType(1);
			deliveryPlan.setStorageGrid(storageGridList.get(0));
			deliveryPlan.setLockers(storageGridList.get(0).getLockers());
			deliveryPlan.setPublish(false);
			deliveryPlan.setInsertTime(new Date());
			
			return deliveryPlan;
		} else {
			return null;
		}
		 
	}
	
	@SuppressWarnings("unchecked")
	public JSONArray getStoreGridConfig(Integer lockersId){
		JSONArray result = new JSONArray();
		
		List<Object[]> list = entityManager.createNativeQuery("select grid_type, grid_size from storage_grid where lockers_id = " + lockersId + " and business_type = 2 group by grid_type, grid_size").getResultList();
		
		int current = 0;
		
		JSONObject gridType = null;
		JSONObject gridSize = null;
		if (list.size() > 0){
			for (int i = 0; i < list.size(); i++) {
				Object[] objs = list.get(i);
				if (i == 0) {
					gridType = new JSONObject();
					gridSize = new JSONObject();
					gridSize.accumulate("large", false);
					gridSize.accumulate("middle", false);
					gridSize.accumulate("small", false);
					
					gridType.accumulate("grid_type", Integer.parseInt(objs[0].toString()));
					current = Integer.parseInt(objs[0].toString());
					
					if (Integer.parseInt(objs[1].toString()) == 1){
						gridSize.element("large", true);
					} else if (Integer.parseInt(objs[1].toString()) == 2){
						gridSize.element("middle", true);
					} else if (Integer.parseInt(objs[1].toString()) == 3) {
						gridSize.element("small", true);
					}
				} else if (current != Integer.parseInt(objs[0].toString())) {
					gridType.accumulate("grid_sizes", gridSize);
					
					result.add(gridType);
					
					gridType = new JSONObject();
					gridSize = new JSONObject();
					gridSize.accumulate("large", false);
					gridSize.accumulate("middle", false);
					gridSize.accumulate("small", false);
					
					gridType.accumulate("grid_type", Integer.parseInt(objs[0].toString()));
					current = Integer.parseInt(objs[0].toString());
					
					if (Integer.parseInt(objs[1].toString()) == 1){
						gridSize.element("large", true);
					} else if (Integer.parseInt(objs[1].toString()) == 2){
						gridSize.element("middle", true);
					} else if (Integer.parseInt(objs[1].toString()) == 3) {
						gridSize.element("small", true);
					}
				} else {
					if (Integer.parseInt(objs[1].toString()) == 1){
						gridSize.element("large", true);
					} else if (Integer.parseInt(objs[1].toString()) == 2){
						gridSize.element("middle", true);
					} else if (Integer.parseInt(objs[1].toString()) == 3) {
						gridSize.element("small", true);
					}
				}
			}
			
			gridType.accumulate("grid_sizes", gridSize);
			result.add(gridType);
		}
		
		return result;
	}

	@SuppressWarnings("unchecked")
	public JSONObject getStoreInfo(String storeCode) {
		List<ProductBatch> productBatchs = entityManager.createQuery("select pb from ProductBatch pb where pb.rfidSn = '" + storeCode + "'").getResultList();
		
		if (productBatchs.size() > 0) {
			JSONObject result = new JSONObject();
			
			ProductBatch productBatch = productBatchs.get(0);

			result.accumulate("store_code", storeCode);
			result.accumulate("reserve_type", productBatch.getDeliveryPlan().getPlanType());
			result.accumulate("publish", productBatch.getDeliveryPlan().isPublish());
			
			List<StorageGridPurchaserNews> list = entityManager.createQuery("select sgpn from StorageGridPurchaserNews sgpn where sgpn.rfidSn = '" + storeCode + "'").getResultList();

			if (list.size() > 0) {
				StorageGridPurchaserNews sgpn = list.get(0);
				result.accumulate("deliver_time", sgpn.getArrivalTime() == null ? null : sgpn.getArrivalTime().getTime());
				result.accumulate("takeout_time", sgpn.getTakeawayTime() == null ? null : sgpn.getTakeawayTime().getTime());
			} else {
				result.accumulate("deliver_time", null);
				result.accumulate("takeout_time", null);
			}
			
			return result;
		}
		
		return null;
	}
}
